﻿using System;
using System.Collections.Generic;
using System.Linq;
using CSLua;
using ICSharpCode.Decompiler.ILAst;
using Mono.Cecil;

namespace TK_CSLua.ILAnalyze
{
	// Token: 0x02000009 RID: 9
	public class LuaType
	{
		// Token: 0x17000008 RID: 8
		// (get) Token: 0x0600002C RID: 44 RVA: 0x00002D74 File Offset: 0x00000F74
		// (set) Token: 0x0600002D RID: 45 RVA: 0x00002D7C File Offset: 0x00000F7C
		public LuaMethod StaticCtor { get; private set; }

		// Token: 0x17000009 RID: 9
		// (get) Token: 0x0600002E RID: 46 RVA: 0x00002D85 File Offset: 0x00000F85
		// (set) Token: 0x0600002F RID: 47 RVA: 0x00002D8D File Offset: 0x00000F8D
		public bool HasCtor { get; private set; }

		// Token: 0x1700000A RID: 10
		// (get) Token: 0x06000030 RID: 48 RVA: 0x00002D96 File Offset: 0x00000F96
		public IEnumerable<LuaType> StaticInitTypes
		{
			get
			{
				return this._staticInitTypes;
			}
		}

		// Token: 0x1700000B RID: 11
		// (get) Token: 0x06000031 RID: 49 RVA: 0x00002D9E File Offset: 0x00000F9E
		public IEnumerable<LuaType> NestedPath
		{
			get
			{
				return this._nestedPath;
			}
		}

		// Token: 0x1700000C RID: 12
		// (get) Token: 0x06000032 RID: 50 RVA: 0x00002DA6 File Offset: 0x00000FA6
		public IEnumerable<LuaType> NestedLuaTypes
		{
			get
			{
				return this._nestLuaLuaTypes;
			}
		}

		// Token: 0x1700000D RID: 13
		// (get) Token: 0x06000033 RID: 51 RVA: 0x00002DAE File Offset: 0x00000FAE
		public IEnumerable<BindItem> BindFields
		{
			get
			{
				return this._bindFields;
			}
		}

		// Token: 0x1700000E RID: 14
		// (get) Token: 0x06000034 RID: 52 RVA: 0x00002DB6 File Offset: 0x00000FB6
		public IEnumerable<LuaMethod> LuaMethods
		{
			get
			{
				return this._methods;
			}
		}

		// Token: 0x1700000F RID: 15
		// (get) Token: 0x06000035 RID: 53 RVA: 0x00002DBE File Offset: 0x00000FBE
		public bool IsNestedType
		{
			get
			{
				return this.ILTypeDef.IsNested;
			}
		}

		// Token: 0x06000036 RID: 54 RVA: 0x00002DCB File Offset: 0x00000FCB
		public LuaType(LuaAssembly LuaAssembly, string luaModule, TypeDefinition ilTypeDef)
		{
			this.LuaAssembly = LuaAssembly;
			this.ILTypeDef = ilTypeDef;
			this.LuaModule = luaModule;
		}

		// Token: 0x06000037 RID: 55 RVA: 0x00002E00 File Offset: 0x00001000
		private void analyzeNeastTypeRecv(TypeDefinition typeDef, List<LuaType> nestedPath, List<LuaType> nestedTypesResult)
		{
			foreach (TypeDefinition nestedType in typeDef.NestedTypes)
			{
				if (AnalyzeUtils.checkBuildType(nestedType))
				{
					LuaType nestDefine = new LuaType(this.LuaAssembly, null, nestedType);
					nestDefine._nestedPath = new List<LuaType>(nestedPath);
					nestDefine.DoAnalyze();
					nestedTypesResult.Add(nestDefine);
					this.analyzeNeastTypeRecv(nestedType, new List<LuaType>(nestedPath)
					{
						nestDefine
					}, nestedTypesResult);
				}
			}
		}

		// Token: 0x06000038 RID: 56 RVA: 0x00002E94 File Offset: 0x00001094
		private bool appendDictSeat(Dictionary<LuaType, HashSet<LuaType>> dict, LuaType key, LuaType value)
		{
			HashSet<LuaType> result;
			if (!dict.TryGetValue(key, out result))
			{
				result = new HashSet<LuaType>();
				dict.Add(key, result);
			}
			return result.Add(value);
		}

		// Token: 0x06000039 RID: 57 RVA: 0x00002EC1 File Offset: 0x000010C1
		private void addUsageReferences(LuaType user, LuaType target)
		{
			this.appendDictSeat(this._usageDict, user, target);
			this.appendDictSeat(this._usageReferences, target, user);
		}

		// Token: 0x0600003A RID: 58 RVA: 0x00002EE4 File Offset: 0x000010E4
		private List<LuaType> analyzeNeastTypes(TypeDefinition typeDef)
		{
			HashSet<string> typeNameCheck = new HashSet<string>();
			typeNameCheck.Add(typeDef.luaIdentifier());
			List<LuaType> result = new List<LuaType>();
			List<LuaType> nestedRootPath = new List<LuaType>
			{
				this
			};
			this.analyzeNeastTypeRecv(typeDef, nestedRootPath, result);
			foreach (LuaType type in result)
			{
				if (typeNameCheck.Contains(type.ILTypeDef.luaIdentifier()))
				{
					throw new Exception("类型重名，暂时不支持嵌套类型重名:" + type.ILTypeDef);
				}
				typeNameCheck.Add(type.ILTypeDef.luaIdentifier());
			}
			return result;
		}

		// Token: 0x0600003B RID: 59 RVA: 0x00002F9C File Offset: 0x0000119C
		private void removeUnusedNestedTypes()
		{
			this.analyzeUsageTypesImpl(this);
			List<LuaType> allTypes = this._nestLuaLuaTypes;
			for (int i = 0; i < allTypes.Count; i++)
			{
				LuaType type = allTypes[i];
				if (type.ILTypeDef.IsNestedPrivate && !this._usageReferences.ContainsKey(type))
				{
					allTypes.RemoveAt(i--);
				}
			}
		}

		// Token: 0x0600003C RID: 60 RVA: 0x00002FF8 File Offset: 0x000011F8
		private void analyzeUsageTypesImpl(LuaType typeDef)
		{
			foreach (LuaMethod luaMethod in typeDef.LuaMethods)
			{
				foreach (ILExpression ilexpression in luaMethod.ILMethodBlock.GetSelfAndChildrenRecursive<ILExpression>(null))
				{
					MemberReference member = ilexpression.Operand as MemberReference;
					if (member != null && member.DeclaringType != null)
					{
						if (member is MethodReference)
						{
							member = ((MethodReference)member).Resolve();
						}
						else if (member is FieldReference)
						{
							member = ((FieldReference)member).Resolve();
						}
						else if (member is PropertyReference)
						{
							member = ((PropertyReference)member).Resolve();
						}
						else if (member is EventReference)
						{
							member = ((EventReference)member).Resolve();
						}
						else if (member is GenericInstanceType)
						{
							member = ((GenericInstanceType)member).Resolve();
						}
						if (member != null)
						{
							LuaType type = LuaType.reslovedNeastTypes.GetOrDefault(member.DeclaringType.Resolve());
							if (type != null && type != typeDef)
							{
								this.addUsageReferences(typeDef, type);
							}
						}
					}
				}
			}
			foreach (TypeDefinition nestedType in typeDef.ILTypeDef.NestedTypes)
			{
				LuaType nestedLuaType = LuaType.reslovedNeastTypes.GetOrDefault(nestedType);
				if (nestedLuaType != null)
				{
					this.analyzeUsageTypesImpl(nestedLuaType);
				}
			}
		}

		// 分析嵌套类型
		private void analyzeNestedTypes()
		{
			this._nestLuaLuaTypes = new List<LuaType>();
			new List<LuaType>().Add(this);
			this._nestLuaLuaTypes = this.analyzeNeastTypes(this.ILTypeDef);
		}

		// Token: 0x0600003F RID: 63 RVA: 0x00003328 File Offset: 0x00001528
		private void analyzeStaticInit()
		{
			this._staticInitTypes = new List<LuaType>();
			if (this.StaticCtor != null)
			{
				this._staticInitTypes.Add(this);
			}
			foreach (LuaType luaType in this._nestLuaLuaTypes)
			{
				if (luaType.StaticCtor != null)
				{
					this._staticInitTypes.Add(luaType);
				}
			}
		}

		// Token: 0x06000040 RID: 64 RVA: 0x000033A8 File Offset: 0x000015A8
		internal void DoAnalyze()
		{
			if (!this.IsNestedType)
			{
				this.analyzeNestedTypes();
			}
			HashSet<string> methodNameCheck = new HashSet<string>();
			this._methods = new List<LuaMethod>();
			foreach (MethodDefinition method in this.ILTypeDef.Methods)
			{
				if (method.HasBody)
				{
					LuaMethod luaMethod = new LuaMethod(this, method);
					luaMethod.DoAnalyze();
					string luaIdentifier = luaMethod.ILMethod.luaIdentifier();
					if (methodNameCheck.Contains(luaIdentifier))
					{
						throw new Exception("发现函数重名，暂时不支持函数重载  method:" + luaMethod.ILMethod);
					}
					methodNameCheck.Add(luaIdentifier);
					this._methods.Add(luaMethod);
					if (method.isCtor())
					{
						this.HasCtor = true;
					}
					else if (method.isStaticCtor())
					{
						this.StaticCtor = luaMethod;
					}
				}
			}
			LuaType.reslovedNeastTypes.Add(this.ILTypeDef, this);
			if (!this.IsNestedType)
			{
				this.removeUnusedNestedTypes();
				this.analyzeStaticInit();
			}
		}

		// Token: 0x04000016 RID: 22
		public readonly string LuaModule;

		// Token: 0x04000017 RID: 23
		public readonly TypeDefinition ILTypeDef;

		// Token: 0x04000018 RID: 24
		public readonly LuaAssembly LuaAssembly;

		// Token: 0x0400001B RID: 27
		private List<LuaType> _staticInitTypes;

		// Token: 0x0400001C RID: 28
		private List<LuaType> _nestedPath;

		// Token: 0x0400001D RID: 29
		private List<LuaType> _nestLuaLuaTypes;

		// Token: 0x0400001E RID: 30
		private List<BindItem> _bindFields;

		// Token: 0x0400001F RID: 31
		private List<LuaMethod> _methods;

		// Token: 0x04000020 RID: 32
		private static Dictionary<TypeDefinition, LuaType> reslovedNeastTypes = new Dictionary<TypeDefinition, LuaType>();

		// Token: 0x04000021 RID: 33
		private Dictionary<LuaType, HashSet<LuaType>> _usageDict = new Dictionary<LuaType, HashSet<LuaType>>();

		// Token: 0x04000022 RID: 34
		private Dictionary<LuaType, HashSet<LuaType>> _usageReferences = new Dictionary<LuaType, HashSet<LuaType>>();
	}
}
